package com.ssyx.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ssyx.common.exception.SsyxException;
import com.ssyx.common.result.ResultCodeEnum;
import com.ssyx.model.product.SkuAttrValue;
import com.ssyx.model.product.SkuImage;
import com.ssyx.model.product.SkuInfo;
import com.ssyx.model.product.SkuPoster;
import com.ssyx.product.service.SkuAttrValueService;
import com.ssyx.product.service.SkuImageService;
import com.ssyx.product.service.SkuInfoService;
import com.ssyx.product.mapper.SkuInfoMapper;
import com.ssyx.product.service.SkuPosterService;
import com.ssyx.vo.product.SkuInfoQueryVo;
import com.ssyx.vo.product.SkuInfoVo;
import com.ssyx.vo.product.SkuStockLockVo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;

/**
* @author 34901
* @description 针对表【sku_info(sku信息)】的数据库操作Service实现
* @createDate 2024-04-27 23:25:07
*/
@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo>
    implements SkuInfoService {

    @Autowired
    private SkuImageService skuImageService;

    @Autowired
    private SkuPosterService skuPosterService;

    @Autowired
    private SkuAttrValueService skuAttrValueService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

//    @Autowired
//    private RabbitService rabbitService;

    //获取sku分页列表
    @Override
    public IPage<SkuInfo> getPage(Page<SkuInfo> pageParams, SkuInfoQueryVo skuInfoQueryVo) {
        String keyword = skuInfoQueryVo.getKeyword();
        Long categoryId = skuInfoQueryVo.getCategoryId();
        String skuType = skuInfoQueryVo.getSkuType();

        LambdaQueryWrapper<SkuInfo> wrapper = new LambdaQueryWrapper<>();
        if (!StringUtils.isEmpty(keyword)) {
            wrapper.like(SkuInfo::getSkuName, keyword);
        }
        if (!StringUtils.isEmpty(categoryId)) {
            wrapper.eq(SkuInfo::getCategoryId, categoryId);
        }
        if (!StringUtils.isEmpty(skuType)) {
            wrapper.eq(SkuInfo::getSkuType, skuType);
        }

        Page<SkuInfo> skuInfoPage = baseMapper.selectPage(pageParams, wrapper);
        return skuInfoPage;
    }

    //新增商品
    @Override
    public void saveSkuInfo(SkuInfoVo skuInfoVo) {
        //添加sku基本信息
        //SkuInfoVo 复制 => SkuInfo
        SkuInfo skuInfo = new SkuInfo();
        BeanUtils.copyProperties(skuInfoVo, skuInfo);
        baseMapper.insert(skuInfo);

        //保存sku海报
        List<SkuPoster> skuPosterList = skuInfoVo.getSkuPosterList();
        if (!CollectionUtils.isEmpty(skuPosterList)) {
            for (SkuPoster skuPoster : skuPosterList) {
                skuPoster.setSkuId(skuInfo.getId());
            }
            skuPosterService.saveBatch(skuPosterList);
        }

        //保存suk图片
        List<SkuImage> skuImagesList = skuInfoVo.getSkuImagesList();
        if (!CollectionUtils.isEmpty(skuImagesList)) {
            for (SkuImage skuImage : skuImagesList) {
                skuImage.setSkuId(skuInfo.getId());
            }
            skuImageService.saveBatch(skuImagesList);
        }

        //保存sku平台属性
        List<SkuAttrValue> skuAttrValueList = skuInfoVo.getSkuAttrValueList();
        if (!CollectionUtils.isEmpty(skuAttrValueList)) {
            for (SkuAttrValue skuAttrValue : skuAttrValueList) {
                skuAttrValue.setSkuId(skuInfo.getId());
            }
            skuAttrValueService.saveBatch(skuAttrValueList);
        }
    }

    //获取商品sku信息
    @Override
    public SkuInfoVo getSkuInfoVoById(Long id) {
        SkuInfoVo skuInfoVo = new SkuInfoVo();

        //skuInfo =>skuInfoVo
        SkuInfo skuInfo = baseMapper.selectById(id);
        BeanUtils.copyProperties(skuInfo, skuInfoVo);

        //SkuPoster
        LambdaQueryWrapper<SkuPoster> skuPosterWrapper = new LambdaQueryWrapper<>();
        skuPosterWrapper.eq(SkuPoster::getSkuId, id);
        List<SkuPoster> skuPosterList = skuPosterService.list(skuPosterWrapper);
        skuInfoVo.setSkuPosterList(skuPosterList);

        //SkuImage
        LambdaQueryWrapper<SkuImage> skuImageWrapper = new LambdaQueryWrapper<>();
        skuImageWrapper.eq(SkuImage::getSkuId, id);
        List<SkuImage> skuImagesList = skuImageService.list(skuImageWrapper);
        skuInfoVo.setSkuImagesList(skuImagesList);

        //SkuAttrValue
        LambdaQueryWrapper<SkuAttrValue> skuAttrWrapper = new LambdaQueryWrapper<>();
        skuAttrWrapper.eq(SkuAttrValue::getSkuId, id);
        List<SkuAttrValue> skuAttrValueList = skuAttrValueService.list(skuAttrWrapper);
        skuInfoVo.setSkuAttrValueList(skuAttrValueList);

        return skuInfoVo;
    }

    //修改商品sku信息
    @Override
    public void updateSkuInfo(SkuInfoVo skuInfoVo) {

        //修改SkuInfo信息
        SkuInfo skuInfo = new SkuInfo();
        BeanUtils.copyProperties(skuInfoVo, skuInfo);
        baseMapper.updateById(skuInfo);

        //获取skuId
        Long skuId = skuInfoVo.getId();

        //先将sku海报中原信息删除,然后将新的信息保存
        LambdaQueryWrapper<SkuPoster> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(SkuPoster::getSkuId, skuId);
        skuPosterService.remove(wrapper1);

        List<SkuPoster> skuPosterList = skuInfoVo.getSkuPosterList();
        if (!CollectionUtils.isEmpty(skuPosterList)) {
            for (SkuPoster skuPoster : skuPosterList) {
                skuPoster.setSkuId(skuId);
            }

            skuPosterService.saveBatch(skuPosterList);
        }


        //先将sku图片中原信息删除,然后将新的信息保存
        LambdaQueryWrapper<SkuImage> wrapper2 = new LambdaQueryWrapper<>();
        wrapper2.eq(SkuImage::getSkuId, skuId);
        skuImageService.remove(wrapper2);

        List<SkuImage> skuImagesList = skuInfoVo.getSkuImagesList();
        if (!CollectionUtils.isEmpty(skuImagesList)) {
            for (SkuImage skuImage : skuImagesList) {
                skuImage.setSkuId(skuId);
            }
            skuImageService.saveBatch(skuImagesList);
        }

        //先将sku平台属性中原信息删除,然后将新的信息保存
        LambdaQueryWrapper<SkuAttrValue> wrapper3 = new LambdaQueryWrapper<>();
        wrapper3.eq(SkuAttrValue::getSkuId, skuId);
        skuAttrValueService.remove(wrapper3);

        List<SkuAttrValue> skuAttrValueList = skuInfoVo.getSkuAttrValueList();
        if (!CollectionUtils.isEmpty(skuAttrValueList)) {
            for (SkuAttrValue skuAttrValue : skuAttrValueList) {
                skuAttrValue.setSkuId(skuId);
            }
            skuAttrValueService.saveBatch(skuAttrValueList);
        }
    }


    //根据id删除商品sku信息
    ////要删除SkuInfo,SkuPoster,SkuImage,SkuAttrValue这4张表对应的信息
    @Override
    public void removeSkuById(Long id) {
        //删除SkuInfo表内信息
        baseMapper.deleteById(id);

        //删除SkuPoster表内信息
        LambdaQueryWrapper<SkuPoster> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(SkuPoster::getSkuId, id);
        skuPosterService.remove(wrapper1);

        //删除SkuImage表内信息
        LambdaQueryWrapper<SkuImage> wrapper2 = new LambdaQueryWrapper<>();
        wrapper2.eq(SkuImage::getSkuId, id);
        skuImageService.remove(wrapper2);

        //删除SkuAttrValue表内信息
        LambdaQueryWrapper<SkuAttrValue> wrapper3 = new LambdaQueryWrapper<>();
        wrapper3.eq(SkuAttrValue::getSkuId, id);
        skuAttrValueService.remove(wrapper3);
    }

    //商品审核
    @Override
    public void check(Long skuId, Integer status) {
        SkuInfo skuInfo = baseMapper.selectById(skuId);
        skuInfo.setCheckStatus(status);
        baseMapper.updateById(skuInfo);
    }

    //商品上下架
    @Override
    public void publish(Long skuId, Integer status) {
        if (status == 1) { //上架
            SkuInfo skuInfo = baseMapper.selectById(skuId);
            skuInfo.setPublishStatus(status);
            baseMapper.updateById(skuInfo);
            //TODO 商品上架 后续会完善：发送mq消息更新es数据
//            rabbitService.sendMessage(MqConst.EXCHANGE_GOODS_DIRECT,
//                                      MqConst.ROUTING_GOODS_UPPER,
//                                      skuId);
        } else { //下架
            SkuInfo skuInfo = baseMapper.selectById(skuId);
            skuInfo.setPublishStatus(status);
            baseMapper.updateById(skuInfo);
            //TODO 商品下架 后续会完善：发送mq消息更新es数据
//            rabbitService.sendMessage(MqConst.EXCHANGE_GOODS_DIRECT,
//                    MqConst.ROUTING_GOODS_LOWER,
//                    skuId);
        }
    }

    //设置新人专享
    @Override
    public void isNewPerson(Long skuId, Integer status) {
        SkuInfo skuInfoUp = new SkuInfo();
        skuInfoUp.setId(skuId);
        skuInfoUp.setIsNewPerson(status);
        baseMapper.updateById(skuInfoUp);
    }

    //获取新人商品(部分)
    @Override
    public List<SkuInfo> findNewPersonList() {
        //条件1 : is_new_person = 1
        //条件2 : publish_status = 1
        //条件3 : 显示其中3条 ,分页实现
        LambdaQueryWrapper<SkuInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SkuInfo::getIsNewPerson, 1)
                .eq(SkuInfo::getPublishStatus, 1)
                .orderByDesc(SkuInfo::getStock); //库存降序

        Page<SkuInfo> pageParam = new Page<>(1, 3);
        IPage<SkuInfo> skuInfoPage = baseMapper.selectPage(pageParam, wrapper);
        List<SkuInfo> skuInfoList = skuInfoPage.getRecords();
        return skuInfoList;
    }

    //获取销量高的商品
    @Override
    public List<SkuInfo> findMaxStockList() {
        //为了方便测试,查询出销量前10的商品
        LambdaQueryWrapper<SkuInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(SkuInfo::getSale); //销量降序

        Page<SkuInfo> pageParam = new Page<>(1, 10);
        IPage<SkuInfo> skuInfoPage = baseMapper.selectPage(pageParam, wrapper);
        List<SkuInfo> skuInfoList = skuInfoPage.getRecords();
        return skuInfoList;
    }

    //根据仓库id + 分类id 进行分页查询
    @Override
    public Page<SkuInfo> getSkuInfoPage(Page<SkuInfo> pageParams, Long categoryId, Long wareId) {
        LambdaQueryWrapper<SkuInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SkuInfo::getWareId, wareId)
                .eq(SkuInfo::getPublishStatus, 1)
                .eq(SkuInfo::getCategoryId, categoryId);
        Page<SkuInfo> skuInfoPage = baseMapper.selectPage(pageParams, wrapper);
        return skuInfoPage;
    }

    //根据仓库id + keyword 查询
    @Override
    public Page<SkuInfo> selectSkuInfoPage(Page<SkuInfo> pageParams, String keyword, Long wareId) {
        LambdaQueryWrapper<SkuInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SkuInfo::getWareId, wareId)
                .eq(SkuInfo::getPublishStatus, 1)
                .like(SkuInfo::getSkuName, keyword);
        Page<SkuInfo> skuInfoPage = baseMapper.selectPage(pageParams, wrapper);
        return skuInfoPage;
    }

    //根据用户提交的相关购物车商品信息,判断是否锁定库存
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Boolean checkAndLock(List<SkuStockLockVo> skuStockLockVoList, String orderNo) {

        if (CollectionUtils.isEmpty(skuStockLockVoList)) {
            throw new SsyxException(ResultCodeEnum.DATA_ERROR);
        }

        // 遍历所有商品，验库存并锁库存，要具备原子性
        skuStockLockVoList.forEach(skuStockLockVo -> {
            checkLock(skuStockLockVo);
        });
        // 只要有一个商品锁定失败，所有锁定成功的商品要解锁库存
        boolean flag = skuStockLockVoList.stream().anyMatch(skuStockLockVo -> !skuStockLockVo.getIsLock());
        //匹配到字段isLock,false,即flag表示锁库存失败,则遍历商品项,解锁所有商品库存(相当于rollback)
        if (flag) {
            skuStockLockVoList.stream().filter(SkuStockLockVo::getIsLock).forEach(skuStockLockVo -> {
                baseMapper.unlockStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
            });
            // 响应锁定状态 失败
            return false;
        }

        // 如果所有商品都锁定成功的情况下，需要缓存锁定信息到redis。以方便将来解锁库存 或者 减库存
        // 以orderToken作为key，以lockVos锁定信息作为value
        redisTemplate.opsForValue().set("orderToken:" + orderNo, JSONObject.toJSONString(skuStockLockVoList));
        return true;
    }


    //验库存并锁库存，要具备原子性
    private void checkLock(SkuStockLockVo skuStockLockVo) {
        //skuId 商品id
        Long skuId = skuStockLockVo.getSkuId();
        //skuNum 商品数量
        Integer skuNum = skuStockLockVo.getSkuNum();
        //公平锁，就是保证客户端获取锁的顺序，跟他们请求获取锁的顺序，是一样的。
        // 公平锁需要排队,谁先申请获取这把锁，谁就可以先获取到这把锁，是按照请求的先后顺序来的。
        //获取锁,这里获取锁,要用一个比较具有代表性的标志做为key,传过来的是一个商品的信息类,所以用skuId做为key
        RLock rLock = this.redissonClient.getFairLock("sku:" + skuId);
        //加锁
        rLock.lock();

        try {
            //验证库存,传入商品id和数量，查询数量库中是否有充足商品
            //总库存-已锁定库存 = 用户购买的商品数量,则表示库存充足,查询能返回商品信息
            //stock - lock_stock > #{skuNum} for update
            SkuInfo skuInfo = baseMapper.checkStock(skuId, skuNum);
            //如果没有满足条件的商品,设置isLock为false,并返回
            if (skuInfo == null) {
                skuStockLockVo.setIsLock(false);
                return;
            }
            //如果有满足条件的商品,则锁定库存 lock_stock = lock_stock + #{skuNum}
            Integer i = baseMapper.lockStock(skuId, skuNum);
            if (i == 1) {
                skuStockLockVo.setIsLock(true);
            }

        } finally {
            //释放锁
            rLock.unlock();
        }
    }

    //根据orderNo,修改产品表库存
    @Override
    public void updateStockByOrderNo(String orderNo) {
        //根据前期缓存在redis中的数据SkuStockLockVo集合,取出可得到订单商品信息
        String skuStockLockVoListString = redisTemplate.opsForValue().get("orderToken:" + orderNo);
        List<SkuStockLockVo> skuStockLockVoList = JSONObject.parseArray(skuStockLockVoListString, SkuStockLockVo.class);
        for (SkuStockLockVo skuStockLockVo : skuStockLockVoList) {
            Integer skuNum = skuStockLockVo.getSkuNum();
            Long skuId = skuStockLockVo.getSkuId();
            SkuInfo skuInfo = baseMapper.selectById(skuId);
            //减库存
            skuInfo.setStock(skuInfo.getStock() - skuNum);
            //加销量
            skuInfo.setSale(skuInfo.getSale() + skuNum);
            //解锁库存
            skuInfo.setLockStock(skuInfo.getLockStock() - skuNum);
        }
        // 解锁库存之后，删除锁定库存的缓存。以防止重复解锁库存
        redisTemplate.delete("orderToken:" + orderNo);
    }

}


